package com.example.word.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.example.word.dto.TemplateRankDTO;
import com.example.word.dto.TemplateStatisticsDTO;
import com.example.word.dto.UniqueViewDTO;
import com.example.word.dto.WordBackInfoDTO;
import com.example.word.mapper.MessageMapper;
import com.example.word.mapper.TemplateMapper;
import com.example.word.mapper.UserInfoMapper;
import com.example.word.mapper.WebsiteConfigMapper;
import com.example.word.pojo.Template;
import com.example.word.pojo.WebsiteConfig;
import com.example.word.service.RedisService;
import com.example.word.service.UniqueViewService;
import com.example.word.service.WordInfoService;
import com.example.word.util.IpUtils;
import com.example.word.vo.PageResult;
import com.example.word.vo.WebsiteConfigVO;
import eu.bitwalker.useragentutils.Browser;
import eu.bitwalker.useragentutils.OperatingSystem;
import eu.bitwalker.useragentutils.UserAgent;
import io.swagger.annotations.ApiModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

import static com.example.word.constant.CommonConst.*;
import static com.example.word.constant.RedisPrefixConst.*;

/**
 * 文档信息服务
 * @author yuwen
 * @date 2023/3/31
 */
@Service
public class WordInfoServiceImpl implements WordInfoService {

    @Autowired
    private RedisService redisService;
    @Autowired
    private WebsiteConfigMapper websiteConfigMapper;
    @Resource
    private HttpServletRequest request;
    @Autowired
    private MessageMapper messageMapper;
    @Autowired
    private UserInfoMapper userInfoMapper;
    @Autowired
    private TemplateMapper templateMapper;
    @Autowired
    private UniqueViewService uniqueViewService;
    @Override
    public WebsiteConfigVO getWebsiteConfig() {
        WebsiteConfigVO websiteConfigVO;
        Object websiteConfig = redisService.get(WEBSITE_CONFIG);
        if(Objects.nonNull(websiteConfig)){
            websiteConfigVO = JSON.parseObject(websiteConfig.toString(), WebsiteConfigVO.class);
        }else{
            String config = websiteConfigMapper.selectById(DEFAULT_CONFIG_ID).getConfig();
            websiteConfigVO = JSON.parseObject(config,WebsiteConfigVO.class);
            redisService.set(WEBSITE_CONFIG, config);
        }
        return websiteConfigVO;
    }

    @Override
    public void report() {
        // 获取ip
        String ipAddress = IpUtils.getIpAddress(request);
        // 获取访问设备
        UserAgent userAgent = IpUtils.getUserAgent(request);
        Browser browser = userAgent.getBrowser();
        OperatingSystem operatingSystem = userAgent.getOperatingSystem();
        // 生成唯一用户标识
        String uuid = ipAddress + browser.getName() + operatingSystem.getName();
        String md5 = DigestUtils.md5DigestAsHex(uuid.getBytes());
        // 判断是否访问
        if (!redisService.sIsMember(UNIQUE_VISITOR, md5)) {
            // 统计游客地域分布
            String ipSource = IpUtils.getIpSource(ipAddress);
            if (StringUtils.isNotBlank(ipSource)) {
                ipSource = ipSource.substring(0, 2)
                        .replaceAll(PROVINCE, "")
                        .replaceAll(CITY, "");
                redisService.hIncr(VISITOR_AREA, ipSource, 1L);
            } else {
                redisService.hIncr(VISITOR_AREA, UNKNOWN, 1L);
            }
            // 访问量+1
            redisService.incr(WORD_VIEWS_COUNT, 1);
            // 保存唯一标识
            redisService.sAdd(UNIQUE_VISITOR, md5);
        }
    }

    @Override
    public WordBackInfoDTO getWordBackInfo() {
        // 查询访问量
        Object count = redisService.get(WORD_VIEWS_COUNT);
        Integer viewsCount = Integer.parseInt(Optional.ofNullable(count).orElse(0).toString());
        // 查询留言量
        Integer messageCount = messageMapper.selectCount(null);
        // 查询用户量
        Integer userCount = userInfoMapper.selectCount(null);
        //查询模板数量
        Integer templateCount = templateMapper.selectCount(null);
        // 查询一周用户量
        List<UniqueViewDTO> uniqueViewList = uniqueViewService.listUniqueViews();
        // 查询模板统计
        List<TemplateStatisticsDTO> templateStatisticsList = templateMapper.listTemplateStatistics();
        // 查询redis对比量前五的模板
        Map<Object, Double> templateMap = redisService.zReverseRangeWithScore(TEMPLATE_COMP_COUNT, 0, 4);

        WordBackInfoDTO wordBackInfoDTO = WordBackInfoDTO.builder()
                .messageCount(messageCount)
                .viewsCount(viewsCount)
                .userCount(userCount)
                .templateCount(templateCount)
                .uniqueViewDTOList(uniqueViewList)
                .templateStatisticsList(templateStatisticsList).build();
        if (CollectionUtils.isNotEmpty(templateMap)) {
            // 查询文章排行
            List<TemplateRankDTO> templateRankDTOList = listTemplateRank(templateMap);
            wordBackInfoDTO.setTemplateRankDTOList(templateRankDTOList);
        }
        return wordBackInfoDTO;
    }
    /**
     * 查询模板排行
     *
     * @param templateMap 模板信息
     * @return {@link List<TemplateRankDTO>} 模板排行
     */
    private List<TemplateRankDTO> listTemplateRank(Map<Object, Double> templateMap) {
        // 提取文章id
        List<Integer> templateIdList = new ArrayList<>(templateMap.size());
        templateMap.forEach((key, value) -> templateIdList.add((Integer) key));
        // 查询文章信息
        return templateMapper.selectList(new LambdaQueryWrapper<Template>()
                .select(Template::getId, Template::getEName)
                .in(Template::getId, templateIdList))
                .stream().map(template -> TemplateRankDTO.builder()
                        .templateName(template.getEName())
                        .compsCount(templateMap.get(template.getId()).intValue())
                        .build())
                .sorted(Comparator.comparingInt(TemplateRankDTO::getCompsCount).reversed())
                .collect(Collectors.toList());
    }

    @Override
    public void updateWebsiteConfig(WebsiteConfigVO websiteConfigVO) {
        // 修改网站配置
        WebsiteConfig websiteConfig = WebsiteConfig.builder()
                .id(1)
                .config(JSON.toJSONString(websiteConfigVO))
                .build();
        websiteConfigMapper.updateById(websiteConfig);
        // 删除缓存
        redisService.del(WEBSITE_CONFIG);
    }
}
